﻿namespace Refract.RIA
{
    using System;
    using System.Collections.Generic;
    using System.ServiceModel.DomainServices.Client;

    using Refract.Data;
    using Refract.MVVM;

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TContext">The type of the context.</typeparam>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <typeparam name="TModel">The type of the model.</typeparam>
    /// <typeparam name="TListEntity">The type of the list entity.</typeparam>
    /// <typeparam name="TListModel">The type of the list model.</typeparam>
    public class RiaDataService<TContext, TEntity, TModel, TListEntity, TListModel> : ReadOnlyRiaDataService<TContext, TEntity, TModel, TListEntity, TListModel>, IDataService<TEntity, TListEntity, TListModel>
        where TContext : DomainContext
        where TEntity : Entity, new()
        where TModel : Model<TEntity>, new()
        where TListEntity : ICollection<TEntity>, new()
        where TListModel : Model<TListEntity>, new()
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="RiaDataService&lt;TContext, TEntity, TModel, TListEntity, TListModel&gt;"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public RiaDataService(TContext context)
            : base(context)
        {
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Add(TEntity entity)
        {
            if (entity.EntityState == EntityState.Detached)
            {
                var entitySet = Context.EntityContainer.GetEntitySet<TEntity>();
                entitySet.Add(entity);
            }
        }

        /// <summary>
        /// Cancels any changes in the context.
        /// </summary>
        public void CancelChanges()
        {
            Context.RejectChanges();
        }

        /// <summary>
        /// Deletes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Delete(TEntity entity)
        {
            var entitySet = Context.EntityContainer.GetEntitySet<TEntity>();
            entitySet.Remove(entity);
        }

        /// <summary>
        /// Saves any changes to the context.
        /// </summary>
        public void Save()
        {
            try
            {
                ProcessCount++;

                Context.SubmitChanges(OnSubmitComplete, null);
            }
            catch (Exception exception)
            {
                throw new DomainOperationException("Error saving a " + typeof(TEntity).Name + ".",
                                                   exception);
            }
        }

        /// <summary>
        /// Called when submit operation is complete.
        /// </summary>
        /// <param name="operation">The operation.</param>
        protected virtual void OnSubmitComplete(SubmitOperation operation)
        {
            OnOperationComplete(operation);
        }

        #endregion Methods
    }
}